#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>  // mkfifo(), open()
#include <sys/stat.h>   // mkfifo(), open()
#include <cerrno>       // errno
#include <cstring>      // strerror()
#include <fcntl.h>      // open()
#include <unistd.h>     // read()
#include <chrono>  // std::chrono::system_clock



using namespace std;

const char* Path = "./pipeFile";

class Object
{
public:
    Object(const string& path): m_pathname(path), start_time(chrono::system_clock::now()) {}

    virtual void Run() = 0;

    virtual ~Object() 
    {
        auto end_time = chrono::system_clock::now();
        chrono::duration<double> elapsed_seconds = end_time - start_time;
        cout << "运行时间: " << elapsed_seconds.count() << "秒" << endl;
    }
protected:
    string m_pathname;
    chrono::time_point<chrono::system_clock> start_time;
};

class Client: public Object
{
public:
    Client(const string& path): Object(path){}

    virtual void Run() override
    {
        int wfd = open(m_pathname.c_str(), O_WRONLY);   // return the new file descriptor (fd)
        if(wfd == -1)  { cout << "error: Client::Run()->open, errno: " << errno << " , error message: " << strerror(errno) << endl; return;}

        string message;
        while(message != "quit")
        {
            std::getline(cin, message);

            int n = write(wfd, message.c_str(), message.size());    // write into named_pipe
            if(n < 0) { cout << "error: Client::Run()->write, errno: " << errno << " , error message: " << strerror(errno) << endl; break;}
            else if(n == 0)
            {
                cout << "Server quit, me too..." << endl;
                break;
            }
        }
        close(wfd);
    }

};

class Server: public Object
{
public:
    Server(const string& path): Object(path){}

    virtual void Run() override
    {
        // make named_pipe
        umask(0);
        int ret = mkfifo(m_pathname.c_str(), 0666);
        if(ret == -1) { cout << "error: Server::Run()->mkfifo, errno: " << errno << " , error message: " << strerror(errno) << endl; return;}
        else
        {
            int rfd = open(m_pathname.c_str(), O_RDONLY);
            if(rfd < 0) {cout << "error: Server::Run()->open, errno: " << errno << " , error message: " << strerror(errno) << endl; return;}
            
            char buffer[1024];
            while(true)
            {
                ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);      // On success, the number of bytes read is returned
                if(n < 0) {cout << "error: Server::Run()->read, errno: " << errno << " , error message: " << strerror(errno) << endl; break;}
                else if(n == 0)
                {
                    cout << "Client quit, me too..." << endl;
                    break;
                }
                else    // read success, no break and read continue
                {
                    buffer[n] = '\0';
                    cout << "Server: " << buffer << endl;
                }
            }
            close(rfd);
        }
        unlink(m_pathname.c_str());
    }
};


